package com.atguigu.netty.dubborpc.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NettyClient {

    private static Logger logger = LoggerFactory.getLogger(Thread.currentThread().getClass());

    // 创建线程池
    private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private static NettyClientHandler nettyClientHandler;
    private static NioEventLoopGroup eventLoopGroup;

    private int count = 0;

    // 编写方法使用代理模式，获取一个代理对象
    public Object getBean(final Class<?> serviceClass, final String providerName) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[]{serviceClass}, (proxy, method, args) -> {

                   logger.info("(proxy, method, args) 进入...." + (++count) + " 次");

                    // 客户端每次调用，都会执行这部分代码
                    if (nettyClientHandler == null) {
                        initClient();
                    }

                    // 设置给服务端的消息
                    // providerName 协议头
                    // args[0] 是客户端调用方法的参数
                    nettyClientHandler.setParams(providerName + args[0]);

                    return executorService.submit(nettyClientHandler).get();

                });
    }


    // 初始化客户端
    private static void initClient() {
        nettyClientHandler = new NettyClientHandler();

         eventLoopGroup = new NioEventLoopGroup();
        try {

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(
                            new ChannelInitializer<SocketChannel>() {
                                @Override
                                protected void initChannel(SocketChannel ch) throws Exception {
                                    ChannelPipeline pipeline = ch.pipeline();
                                    pipeline.addLast(new StringDecoder());
                                    pipeline.addLast(new StringEncoder());
                                    pipeline.addLast(nettyClientHandler);
                                }
                            }
                    );
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 7000).sync();
            logger.info("netty客户端connect");
            //2
            channelFuture.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {                    //3
                    logger.info("netty客户端启动成功！");
                } else {
                    Throwable cause = future.cause();        //6
                    cause.printStackTrace();
                }
            });

            ChannelFuture channelFuture1 = channelFuture.channel().closeFuture();

            channelFuture1.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {                    //3
                    logger.info("netty客户端关闭成功！");
                } else {
                    Throwable cause = future.cause();        //6
                    cause.printStackTrace();
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void closeClient() {
        eventLoopGroup.shutdownGracefully();
    }


}
